/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * ScrollableStripeTable.java
 *
 * Created on 27/11/2011, 22:58:04
 */
package bgu.sonar.util.ui.tables;

import bgu.sonar.util.ui.models.AbstractTabularModel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.FocusListener;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelListener;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.swing.DropMode;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.TransferHandler;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;

/**
 *
 * @author bennyl
 */
public class ScrollableStripeTable extends javax.swing.JPanel {

    private final StripeTableHeader HEADER_RENDERER = new StripeTableHeader();
    private Map<String, Integer> columnWidth = new HashMap<>();
    private boolean showingGrid = true;
    private boolean showHeaders = true;

    /**
     * Creates new form ScrollableStripeTable
     */
    public ScrollableStripeTable() {
        initComponents();
        addColumnListener();

        jScrollPane1.setViewport(new JViewport() {
            boolean repainting = false;

            @Override
            public void paint(Graphics g) {

                if ((table.getRowHeight() + 1) * (table.getRowCount() + 1) > getSize().getHeight()) {
                    super.paint(g);
                    return;
                }

                if (!repainting) {
                    repainting = true;
                    table.paint(g);
                    repainting = false;
                }
            }
        });

        jScrollPane1.getViewport().setBackground(Color.red);

        TableModel model = table.getModel();
        table.setModel(new DefaultTableModel());
        table.setModel(model);
        jScrollPane1.setViewportView(table);

        jScrollPane1.setBorder(new EmptyBorder(0, 0, 0, 0));
    }

    @Override
    public synchronized void addFocusListener(FocusListener l) {
        table.addFocusListener(l);
    }

    @Override
    public synchronized void addKeyListener(KeyListener l) {
        table.addKeyListener(l);
    }

    @Override
    public synchronized void addMouseMotionListener(MouseMotionListener l) {
        table.addMouseMotionListener(l);
    }

    @Override
    public synchronized void addMouseWheelListener(MouseWheelListener l) {
        table.addMouseWheelListener(l);
    }

    public void notifyChange() {
        tableChanged(new TableModelEvent(getModel()));
    }

    public void tableChanged(TableModelEvent e) {
        table.tableChanged(e);
    }

    @Override
    public void setTransferHandler(TransferHandler newHandler) {
        table.setTransferHandler(newHandler);
    }

    @Override
    public TransferHandler getTransferHandler() {
        return table.getTransferHandler();
    }

    public final void setDropMode(DropMode dropMode) {
        table.setDropMode(dropMode);
    }

    public final DropMode getDropMode() {
        return table.getDropMode();
    }

    public void setMultiSelectionEnabled(boolean multiSelection) {
        if (multiSelection) {
            table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        } else {
            table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        }
    }

    public boolean isMultiSelectionEnabled() {
        return table.getSelectionModel().getSelectionMode() == ListSelectionModel.SINGLE_SELECTION ? false : true;
    }

    public void setDragEnabled(boolean b) {
        table.setDragEnabled(b);
    }

    public boolean getDragEnabled() {
        return table.getDragEnabled();
    }

    @Override
    public synchronized void addMouseListener(MouseListener l) {
        table.addMouseListener(l);
    }

    public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) {
        table.setDefaultRenderer(columnClass, renderer);
    }

    public TableCellRenderer getDefaultRenderer(Class<?> columnClass) {
        return table.getDefaultRenderer(columnClass);
    }

    public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor) {
        table.setDefaultEditor(columnClass, editor);
    }

    public TableCellEditor getDefaultEditor(Class<?> columnClass) {
        return table.getDefaultEditor(columnClass);
    }

    public void setShowHeaders(boolean showHeaders) {
        this.showHeaders = showHeaders;

        table.getTableHeader().setVisible(showHeaders);
        table.getTableHeader().setPreferredSize(showHeaders ? null : new Dimension(-1, 0));
    }

    public boolean isShowHeaders() {
        return showHeaders;
    }

    public void setRowSelectionAllowed(boolean rowSelectionAllowed) {
        table.setRowSelectionAllowed(rowSelectionAllowed);
    }

    public boolean getRowSelectionAllowed() {
        return table.getRowSelectionAllowed();
    }

    public void setColumnSelectionAllowed(boolean columnSelectionAllowed) {
        table.setColumnSelectionAllowed(columnSelectionAllowed);
    }

    public boolean getColumnSelectionAllowed() {
        return table.getColumnSelectionAllowed();
    }

    public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
        table.setCellSelectionEnabled(cellSelectionEnabled);
    }

    public boolean getCellSelectionEnabled() {
        return table.getCellSelectionEnabled();
    }

    public int getSelectedRow() {
        return table.getSelectedRow();
    }

    public int getSelectedColumn() {
        return table.getSelectedColumn();
    }

    public int[] getSelectedRows() {
        return table.getSelectedRows();
    }

    public int[] getSelectedColumns() {
        return table.getSelectedColumns();
    }

    public int getSelectedRowCount() {
        return table.getSelectedRowCount();
    }

    public int getSelectedColumnCount() {
        return table.getSelectedColumnCount();
    }

    public Color getSelectionForeground() {
        return table.getSelectionForeground();
    }

    public Color getSelectionBackground() {
        return table.getSelectionBackground();
    }

    public void setRowHeight(int rowHeight) {
        table.setRowHeight(rowHeight);
    }

    public int getRowHeight() {
        return table.getRowHeight();
    }

    @Override
    public void setForeground(Color fg) {
        if (table != null) {
            table.setForeground(fg);
        } else {
            super.setForeground(fg);
        }

    }

    @Override
    public Color getForeground() {
        if (table != null) {
            return table.getForeground();
        } else {
            return super.getForeground();
        }
    }

    public Color getHeaderForeground() {
        return HEADER_RENDERER.getForeground();
    }

    public void setHeaderForeground(Color fg) {
        HEADER_RENDERER.setForeground(fg);
    }

    public Color getHeaderBackground() {
        return HEADER_RENDERER.getBackground();
    }

    public void setHeaderBackground(Color bg) {
        HEADER_RENDERER.setBackground(bg);
    }

    public void setOddRowColor(Color oddRowColor) {
        table.setOddRowColor(oddRowColor);
    }

    public void setEvenRowColor(Color evenRowColor) {
        table.setEvenRowColor(evenRowColor);
    }

    public Color getOddRowColor() {
        return table.getOddRowColor();
    }

    public Color getEvenRowColor() {
        return table.getEvenRowColor();
    }

    public void setModel(TableModel dataModel) {
        table.setModel(dataModel);
    }

    public void setShowGridLines(boolean show) {
        table.setShowGrid(show);
        if (show) {
            table.setIntercellSpacing(new Dimension(1, 1));
        } else {
            table.setIntercellSpacing(new Dimension(0, 0));

        }
        showingGrid = show;
    }

    public boolean isShowGridLines() {
        return showingGrid;
    }

    public TableModel getModel() {
        return table.getModel();
    }

    public void setColumnWidth(String columnName, int max) {
        columnWidth.put(columnName, max);
        if (table.getModel() instanceof AbstractTabularModel) {
            AbstractTabularModel model = (AbstractTabularModel) table.getModel();
            for (int i = 0; i < table.getColumnCount(); i++) {
                final String cname = model.getColumnName(i);

                if (cname.equals(columnName)) {
                    table.getColumnModel().getColumn(i).setMaxWidth(columnWidth.get(cname));
                    table.getColumnModel().getColumn(i).setMinWidth(columnWidth.get(cname));
                    return;
                }
            }
        }
    }

    private void addColumnListener() {
        table.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
            @Override
            public void columnAdded(TableColumnModelEvent e) {
                final Enumeration<TableColumn> cols = table.getColumnModel().getColumns();
                while (cols.hasMoreElements()) {
                    TableColumn col = cols.nextElement();
                    col.setHeaderRenderer(HEADER_RENDERER);
                }

                if (table.getModel() instanceof AbstractTabularModel) {
                    AbstractTabularModel model = (AbstractTabularModel) table.getModel();
                    final String cname = model.getColumnName(e.getToIndex());

                    if (columnWidth.containsKey(cname)) {
                        table.getColumnModel().getColumn(e.getToIndex()).setMaxWidth(columnWidth.get(cname));
                        table.getColumnModel().getColumn(e.getToIndex()).setMinWidth(columnWidth.get(cname));
                    }
                    if (model.getColumnClass(e.getToIndex()) == Boolean.class
                            && model.getColumnIcon(e.getToIndex()) != null) {
                        table.getColumnModel()
                                .getColumn(e.getToIndex()).setMaxWidth(24);
                    }
                }
            }

            @Override
            public void columnRemoved(TableColumnModelEvent e) {
            }

            @Override
            public void columnMoved(TableColumnModelEvent e) {
            }

            @Override
            public void columnMarginChanged(ChangeEvent e) {
            }

            @Override
            public void columnSelectionChanged(ListSelectionEvent e) {
            }
        });
    }

    public void addSelectionListener(ListSelectionListener l) {
        table.getSelectionModel().addListSelectionListener(l);
    }

    public void removeSelectionListener(ListSelectionListener l) {
        table.getSelectionModel().removeListSelectionListener(l);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        final ScrollableStripeTable table = new ScrollableStripeTable();
        frame.setContentPane(table);
        frame.pack();
        frame.setVisible(true);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        table = new bgu.sonar.util.ui.tables.StripeTable();

        setLayout(new java.awt.BorderLayout());

        jScrollPane1.setBackground(new java.awt.Color(51, 51, 51));
        jScrollPane1.setBorder(null);

        table.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        table.setRowHeight(20);
        jScrollPane1.setViewportView(table);

        add(jScrollPane1, java.awt.BorderLayout.CENTER);
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JScrollPane jScrollPane1;
    private bgu.sonar.util.ui.tables.StripeTable table;
    // End of variables declaration//GEN-END:variables
}
